home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1998 / MacHack 1998.toast / Papers / C++ Exceptions / µShell / Core Utilities / Object.cp < prev    next >
Encoding:
Text File  |  1998-06-12  |  7.3 KB  |  332 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        Object.cp
  3.  
  4.     Contains:    Support for Reference Counted Objects
  5.     Written by: Steve Sisak
  6.     Copyright:    © 1996-98 by Steve Sisak, all rights reserved.
  7.  */
  8.  
  9. #ifndef __OBJECT__
  10. #include "Object.h"
  11. #endif
  12. #ifndef __EXCEPTIONS__
  13. #include "Exceptions.h"
  14. #endif
  15. #ifndef __DEBUGWRITE__
  16. #include "DebugWrite.h"
  17. #endif
  18. #ifndef __THREADS__
  19. #include <Threads.h>
  20. #endif
  21.  
  22. typedef struct type_info_struct type_info_struct;    //    forward
  23.  
  24. typedef struct type_info_base_list {    //    type info base list
  25.     type_info_struct    *baseti;        //    pointer to bases type_info struct (0: end of list)
  26.     long                offset;            //    offset of base in main class (0x80000000 : ambiguous/no access list follows
  27. }    type_info_base_list;
  28.  
  29. typedef struct type_info_ambighead {    //    type ambiguous/no access base list header
  30.     void                *baseti;        //    pointer to bases type_info struct (0: end of list)
  31.     long                offset;            //    offset of base in main class (|=0x80000000)
  32.     long                bases;            //    number of type_info_base_list elements (public bases)
  33. }    type_info_ambighead;
  34.  
  35. struct type_info_struct {                //    type info data structure
  36.     char                *tname;            //    pointer to type name
  37.     type_info_base_list    *baselist;        //    pointer to base list
  38. };
  39.  
  40. typedef struct RTTIVTableHeader {        //    RTTI header in a vtable
  41.     type_info_struct    *type_info_ptr;    //    pointer to complete class type_info struct
  42.     long                complete_offset;//    offset of complete class
  43. }    RTTIVTableHeader;
  44.  
  45.  
  46. //==============================================================================
  47.  
  48. #pragma segment Main
  49.  
  50. DefineClassNoBaseAbstract(TObject);
  51.  
  52. //------------------------------------------------------------------------------
  53. #pragma segment Main
  54.  
  55. #if qDebug
  56.     TObject::~TObject()
  57.     {
  58.         if (fReferenceCount != 0)
  59.         {
  60.             DebugWrite("\p~Object() - deleting ");
  61.             WriteToDebugger(false);
  62.             DebugWrite("\p with ");
  63.             DebugWriteNum(fReferenceCount);
  64.             DebugWriteLn("\p active reference(s)", qDebug);
  65.         }
  66.     }
  67. #endif
  68.  
  69. //------------------------------------------------------------------------------
  70. #pragma segment Main
  71.  
  72. void TObject::Initialize()
  73. {
  74. #if qObjectInspector || qDebug
  75.     void*                base    = dynamic_cast<void*>(this);
  76. #endif
  77.  
  78. #if qDebug
  79.     RTTIVTableHeader*    vtable    = *(RTTIVTableHeader**) &(&fClassOffset)[1];
  80.  
  81.     fBaseAddress    = base;
  82.     fClassName         = vtable->type_info_ptr->tname;
  83.  
  84.     unsigned long freeStack;
  85.  
  86.     OSErr err = ThreadCurrentStackSpace(kCurrentThreadID, &freeStack);
  87.     
  88.     if (err != noErr || freeStack < 10000)
  89.     {
  90.         DebugWriteLn("\pPossible infinite recursion (<10k stack left)", true);
  91.     }
  92. #endif
  93.  
  94. #if qObjectInspector
  95.     if (!IsInitialized())    // ClassID not set up yet
  96.     {
  97.         const ClassDesc* desc = GetClassDescDynamic();
  98.  
  99.         if (desc != nil)
  100.         {
  101.             desc->RegisterObject(*this, base);
  102.         }
  103.     }
  104. #endif
  105. }
  106.  
  107. //------------------------------------------------------------------------------
  108. #pragma segment Main
  109.  
  110. void TObject::Finalize()
  111. {
  112. #if qDebug
  113.     if (fReferenceCount != 1)
  114.     {
  115.         // We keep duplicate warning code here as there is more valuable info
  116.         // for the programmer on the stack than in ~TObject()
  117.  
  118.         DebugWrite("\pTObject::Finalize() - finalizing ");
  119.         WriteToDebugger(false);
  120.  
  121.         if (fReferenceCount == 0)
  122.         {
  123.             DebugWriteLn("\p never initilaized", qDebug);
  124.         }
  125.         else
  126.         {
  127.             DebugWrite("\p with ");
  128.             DebugWriteNum(fReferenceCount);
  129.             DebugWriteLn("\p active reference(s)", qDebug);
  130.         }
  131.     }
  132. #endif
  133. }
  134.  
  135. //------------------------------------------------------------------------------
  136. #pragma segment Main
  137.  
  138. void TObject::Delete()
  139. {
  140.     FinalizeObject(this);
  141.  
  142.     delete this;
  143. }
  144.  
  145. //------------------------------------------------------------------------------
  146. #pragma segment Main
  147.  
  148. TObject* TObject::DeepClone() const
  149. {
  150.     return nil;
  151. }
  152.  
  153. //------------------------------------------------------------------------------
  154. #pragma segment Main
  155.  
  156. #if qDebug
  157. const char* TObject::GetClassName() const
  158. {
  159.     return fClassName;
  160. }
  161.  
  162. const void* TObject::GetBaseAddress() const
  163. {
  164.     return fBaseAddress;
  165. }
  166.  
  167. void TObject::WriteToDebugger(bool flush) const
  168. {
  169.     const char* name = GetClassName();
  170.     const void* base = GetBaseAddress();
  171.  
  172.     DebugWriteTypeAtAddress(name, base, flush ? kDebugWriteFlush : kDebugWrite);
  173. }
  174. #endif
  175.  
  176. //------------------------------------------------------------------------------
  177. #pragma segment Main
  178.  
  179. void TObject::NilObjectReference()
  180. {
  181. #if qDebug
  182.     SysBreakFunc("\pNilObjectReference\n");
  183.     Debugger();
  184. #endif
  185.  
  186.     Throw(ePointerNil);
  187. }
  188.  
  189. //------------------------------------------------------------------------------
  190. #pragma segment Main
  191.  
  192. void TObject::InitializeObject(const TObject* obj)
  193. {
  194.     if (obj)
  195.     {
  196.         if (obj->fReferenceCount == 0)
  197.         {
  198.             const_cast<TObject*>(obj)->Initialize();
  199.             const_cast<TObject*>(obj)->fReferenceCount = 1;
  200.         }
  201.     }
  202. }
  203.  
  204. //------------------------------------------------------------------------------
  205. #pragma segment Main
  206.  
  207. void TObject::FinalizeObject(const TObject* obj)
  208. {
  209.     if (obj)
  210.     {
  211.         const_cast<TObject*>(obj)->Finalize();
  212.         const_cast<TObject*>(obj)->fReferenceCount = 0;
  213.     }
  214. }
  215.  
  216. //------------------------------------------------------------------------------
  217. #pragma segment Main
  218.  
  219. void TObject::DeleteObject(const TObject* obj)
  220. {
  221.     if (obj)
  222.     {
  223.         const_cast<TObject*>(obj)->Delete();
  224.     }    
  225. }
  226.  
  227. //------------------------------------------------------------------------------
  228. #pragma segment Main
  229.  
  230. TObject* TObject::NewObjectRef(const TObject* obj)
  231. {
  232.     if (obj)
  233.     {
  234.         obj->NewReference();
  235.     }
  236.  
  237.     return const_cast<TObject*>(obj);
  238. }
  239.  
  240. //------------------------------------------------------------------------------
  241. #pragma segment Main
  242.  
  243. TObject& TObject::NewObjectRef(const TObject& obj)
  244. {
  245.     if (&obj == nil)
  246.     {
  247. #if qDebug
  248.         Debugger();
  249. #endif
  250.         NilObjectReference();
  251.     }
  252.  
  253.     return *NewObjectRef(&obj);
  254. }
  255.  
  256. //------------------------------------------------------------------------------
  257. #pragma segment Main
  258.  
  259. TObject* TObject::DeleteObjectRef(const TObject* obj)
  260. {
  261.     if (obj)
  262.     {
  263.         const_cast<TObject*>(obj)->DeleteReference();
  264.     }
  265.  
  266.     return nil;
  267. }
  268.  
  269. //------------------------------------------------------------------------------
  270. //    TObject::SwapObjectReference - this routine increments the reference count
  271. //    of one object and decrements the reference count of another atomically. 
  272. //------------------------------------------------------------------------------
  273.  
  274. #pragma segment Main
  275. TObject* TObject::SwapObjectRef(const TObject* dec, const TObject* inc)
  276. {
  277.     if (dec != inc)                    // cheap optimization
  278.     {
  279.         if (inc)                    // increment new object count first in
  280.         {                            // case we're indirectly referencing
  281.             inc->NewReference();    // the same object
  282.         }
  283.  
  284.         if (dec)                    // now decrement the count of the dec
  285.         {                            // object, if we fail, we also need to 
  286.             try                        // kill the reference we created to
  287.             {                        // the new object
  288.                 dec->DeleteReference();
  289.             }
  290.             catch(...)
  291.             {
  292.                 DeleteObjectRef(inc);
  293.             }
  294.         }
  295.     }
  296.  
  297.     return const_cast<TObject*>(inc);
  298. }
  299.  
  300.  
  301. #pragma segment Main
  302. TObject& TObject::SwapObjectRef(const TObject& dec, const TObject& inc)
  303. {
  304.     if (&inc == nil || &dec == nil)    // this would be bad
  305.     {
  306.         NilObjectReference();
  307.     }
  308.  
  309.     return *SwapObjectRef(&inc, &dec);
  310. }
  311.  
  312. //------------------------------------------------------------------------------
  313. #pragma segment Main
  314.  
  315. ObjectInitializer::ObjectInitializer(const TObject& obj)
  316. :    fObject(obj)
  317. {
  318.     TObject::InitializeObject(&obj);
  319. }
  320.  
  321. //------------------------------------------------------------------------------
  322. #pragma segment Main
  323.  
  324. ObjectInitializer::~ObjectInitializer()
  325. {
  326.     TObject::FinalizeObject(&fObject);
  327. }
  328.  
  329. //------------------------------------------------------------------------------
  330. #pragma segment Main
  331.  
  332.